
#####################################################
#
# 通用Makefile
# 支持多级文件，通用编译
# 编写人：wmh
# 编写时间：2021/08/05
# 参考及使用参见注释及makefile.md
#
#####################################################

# 1.目录选项，按目录存放，一般无需更改
#****************************************************
# 项目目录
DIR := .
# 可执行文件输出目录
OUT_DIR := $(DIR)/out
# .o .d文件存放路径
TOP_TMP_DIR := $(DIR)/tmp
# 顶层的源文件路径、头文件路径、动态库文件路径
TOP_SUBS_DIR := $(DIR)/src
TOP_INCS_DIR := $(DIR)/inc
TOP_LIBS_DIR := $(DIR)/lib
# 项目间公共资源路径
COM_DIR:=..
#****************************************************


# 2.具体工程选项，移植更改项较多
#****************************************************
# 源文件扩展名
EXTENSION := c

# 生成的可执行文件名
APP_NAME := app1
EXE := $(OUT_DIR)/$(APP_NAME)

# 源文件路径，空格区分 可以继续添如
SUBS_DIR := $(TOP_SUBS_DIR) $(TOP_SUBS_DIR)/ext

# 头文件路径，空格区分 可以继续添如
INCS_DIR := $(TOP_INCS_DIR) $(TOP_INCS_DIR)/ext

# 动态库文件路径，空格区分 可以继续添如
LIBS_DIR :=$(TOP_LIBS_DIR)

include $(COM_DIR)/com/com_src
#****************************************************


# 3.文件处理选项，无需更改
#****************************************************
# 找到给定源文件路径的所有源文件 
SOURCE := $(foreach dir,$(SUBS_DIR), $(wildcard $(dir)/*.$(EXTENSION)))
# 根据源文件目录创建对象文件目录，如./src/ext 转为 ./tmp/ext，解决对象文件生成时无相应目录问题
TMP_DIRS := $(foreach dir,$(SUBS_DIR), $(patsubst $(TOP_SUBS_DIR)%,$(TOP_TMP_DIR)%, $(dir)))
TMP_DIRS := $(foreach dir,$(TMP_DIRS), $(patsubst $(COM_DIR)/com/src%,$(COM_DIR)/com/tmp%, $(dir)))
#$(warning $(TMP_DIRS))
# 对象文件生成路径
# 更改扩展名，更改生成路径
#OBJ_FILES := $(patsubst %.$(EXTENSION),%.o, $(SOURCE))

# 改后缀
OBJ_FILES := $(SOURCE:.$(EXTENSION)=.o)
OBJ_FILES := $(patsubst $(TOP_SUBS_DIR)/%,$(TOP_TMP_DIR)/%, $(OBJ_FILES))
OBJ_FILES := $(patsubst $(COM_DIR)/com/src/%,$(COM_DIR)/com/tmp/%, $(OBJ_FILES))
#$(warning $(OBJ_FILES))

# 依赖文件生成路径
# 更改扩展名，更改生成路径，只用于deps目标的实现
#DEP_FILES:= $(patsubst %.$(EXTENSION),%.d, $(SOURCE))
#DEP_FILES:= $(patsubst $(TOP_SUBS_DIR)/%,$(TOP_TMP_DIR)/%, $(DEP_FILES))
#DEP_FILES := $(patsubst %.o,%.d, $(OBJ_FILES))
DEP_FILES := $(OBJ_FILES:.o=.d)
# 下面两行定义的变量，每次都是空，我不理解用意，先留着
# $(wildcard $(DEP_FILES))查找依赖文件是否存在
# 找到不存在的依赖文件。按理应该有，因为DEP_FILES是从源文件来的，但是文件里又不存在
# 后续删除同名对象文件
MISSING_DEP_FILES := $(filter-out $(wildcard $(DEP_FILES)),$(DEP_FILES))
MISSING_DEP_FILES_SOURCES := $(wildcard $(patsubst %.d,%.$(EXTENSION),$(MISSING_DEP_FILES)))

# 链接动态库
# 形式1，直接给出路径+库文件名(编译运行都采用soname)
#LIB := $(foreach dir,$(LIBS_DIR), $(wildcard $(dir)/*.so.[0-9]))
LIB := $(foreach dir,$(LIBS_DIR),$(wildcard $(dir)/*.so*))
#LIB := $(foreach dir,$(LIBS_DIR),$(addprefix $(dir)/,$(shell ls $(dir)| grep '.so.[0-9]\+')) )
#$(warning $(LIB))
# 形式2，使用"-l库名"，并指定库的路径
#LIB := $(foreach dir,$(LIBS_DIR),$(wildcard $(dir)/*.so))
#LIB := $(notdir $(LIB))
# 可以把libc.soxxxx换成libc，即去掉.后版本信息
#LIB := $(foreach lib,$(LIB),$(shell echo $(lib)|awk -F '.' '( print $$1 )'))
#LIB := $(patsubst lib%,-l%,$(LIB))
#****************************************************


# 4.编译、链接选项
#****************************************************
# 4.1 交叉编译器选项
CROSS_COMPILE = /home/poppy/wmh_test/openwrt-toolchain-ramips-mt76x8_gcc-7.3.0_musl.Linux-x86_64/toolchain-mipsel_24kc_gcc-7.3.0_musl/bin/mipsel-openwrt-linux-
AS		= $(CROSS_COMPILE)as
LD		= $(CROSS_COMPILE)ld
CC		= $(CROSS_COMPILE)gcc
CPP		= $(CC) -E
AR		= $(CROSS_COMPILE)ar
NM		= $(CROSS_COMPILE)nm

# 警告，优化
CFLAGS = -Wall -O2
# 头文件处理
CFLAGS += $(addprefix -I,$(INCS_DIR))
# 生成.d依赖文件，输出的依赖文件中，不包含标准头文件
CFLAGS += -MMD

# 库文件处理，自己制作的的库。链接时，需要指定本地库的路径
LDFLAGS += $(LIB)
# 编译时制作库路径，每一个库文件路径都增加前缀"-L"
# 链接动态库时采用形式1，就不需要指定路径
#LDFLAGS += $(addprefix -L,$(LIBS_DIR))
# [可选] 运行时库路径，也可以直接把运行缺失的库放到默认库路径/usr/lib、/lib
LDFLAGS += -Wl,-rpath=/usr/com_lib
# [可选] 库的依赖库，加入这个参数-rpath-link， 因为one shared library may require another
#shared_link :=-Wl,-rpath-link=
#LDFLAGS += $(addprefix $(shared_link), $(LIBS_DIR))
#****************************************************


# 其他
#****************************************************
RM := rm -f
MKDIR := mkdir -p
SEND := sshpass -p [passwd scp data_dir user@host:dir]
#****************************************************



# 以下无需更改
# 这样写，可以编译多种目标，和目标组合，比如rebuild就是执行clean后再执行all，妙
.PHONY : all deps objs clean rebuild send tmpdir

all : tmpdir $(EXE)

deps : tmpdir $(DEP_FILES)
	$(CC) -MM -MMD $(SOURCE)

objs : tmpdir $(OBJ_FILES)

clean:
	@$(RM) $(shell find -name "*.o")
	@$(RM) $(shell find -name "*.d")
	@$(RM) $(EXE)
	@$(RM) $(shell find ../com/ -name "*.o")
	@$(RM) $(shell find ../com/ -name "*.d")

rebuild: clean all 

send:
	$(SEND)

tmpdir:
	@$(MKDIR) $(TMP_DIRS)

# %包含路径和名称
$(TOP_TMP_DIR)/%.o: $(TOP_SUBS_DIR)/%.c
	$(CC) -c $(CFLAGS) $< -o $@

$(COM_DIR)/com/tmp/%.o : $(COM_DIR)/com/src/%.c
	$(CC) -c $(CFLAGS) $< -o $@

#删除和缺失的依赖文件同名的对象文件
ifneq ($(MISSING_DEP_FILES),)
$(MISSING_DEP_FILES) :
	@$(RM) $(patsubst %.d,%.o,$@)
endif

-include $(DEP_FILES)

$(EXE) : $(OBJ_FILES)
	$(CC) -o $(EXE) $(OBJ_FILES) $(LDFLAGS)

